#include "stdafx.h"

// https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-getting-and-setting-certificate-properties

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#pragma comment(lib, "crypt32.lib")

//--------------------------------------------------------------------
//   Copyright (C) Microsoft.  All rights reserved.
//   Declare functions MyHandleError and My_Wait.
//   These functions are defined at the end of the file.

void MyHandleError(char *s);

void My_Wait();

//--------------------------------------------------------------------
//  Begin main.

void main(void)
{

	//--------------------------------------------------------------------
	// This program shows all of the certificates in a 
	// certificate store and lists all of the property ID numbers of all 
	// of the certificate contexts.

	// It also adds an enhanced key usage identifier to every other
	// certificate.

	//--------------------------------------------------------------------
	//  Declare and initialize local variables.

	HANDLE           hCertStore;
	PCCERT_CONTEXT   pCertContext = NULL;
	CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo;
	char pszNameString[256];
	char pszStoreName[256];
	char fResponse;

	wchar_t suTempName[] = L"My Temp Name.";
	CRYPT_DATA_BLOB  Friendly_Name_Blob = {
		wcslen(suTempName)*sizeof(wchar_t),
		(BYTE*)suTempName
	};

	void*            pvData;
	DWORD            cbData;
	DWORD            dwFlags = CERT_STORE_NO_CRYPT_RELEASE_FLAG;
	DWORD            dwPropId = 0;   // 0 must be used on the first
									 // call to the function. After that,
									 // the last returned property ID is 
									 // passed.
	LPCSTR  pszUsageIdentifier = szOID_RSA_RC4;
	int count = 0;

	fprintf(stderr, "Please enter the store name :");
	scanf_s("%s", pszStoreName, _countof(pszStoreName));
	fprintf(stderr, "The store name is %s .\n", pszStoreName);
	My_Wait();

	//--------------------------------------------------------------------
	// Open the named system certificate store. 

	if (!(hCertStore = CertOpenSystemStore(
		NULL,
		pszStoreName)))
	{
		MyHandleError("Store not opened.");
	}

	//--------------------------------------------------------------------
	// The file is open. Continue.
	// In a loop, use CertEnumCertificatesInStore to get the each
	// certificate in the store. 

	while (pCertContext = CertEnumCertificatesInStore(
		hCertStore,
		pCertContext))
	{
		//--------------------------------------------------------------------
		//  First, retrieve and print the subject name from the certificate.

		if (CertGetNameString(
			pCertContext,
			CERT_NAME_SIMPLE_DISPLAY_TYPE,
			0,
			NULL,
			pszNameString,
			128))
		{
			printf("\nNew Cert for %s \n", pszNameString);
		}
		else
		{
			printf("The get name failed.\n");
		}
		//--------------------------------------------------------------------
		//  Set the enhanced key usage property on every other certificate.

		if (count == 0)
		{
			count++;
			if (CertAddEnhancedKeyUsageIdentifier(
				pCertContext,
				pszUsageIdentifier))
			{
				printf("Enhanced key usage set.\n");
			}
			else
			{
				printf("Enhanced key usage was not set.\n");
			}
		}
		else
		{
			//   Do not set the usage, but reset the counter so that the property
			//   will be set on the next certificate.
			//   Ask if the user would like to set a display name.
			//   
			printf("Would you like to set the display name ?");
			scanf_s("%c", &fResponse, 1);
			if (fResponse == 'y')
			{
				if (CertSetCertificateContextProperty(
					pCertContext,
					CERT_FRIENDLY_NAME_PROP_ID,
					0,
					&Friendly_Name_Blob))
				{
					printf("A name has been set.\n");
				}
				else
				{
					printf("The display name was not set.\n");
				}
			}
			count = 0;
		}

		//--------------------------------------------------------------------
		// In a loop, find all of the property IDs for the given certificate.
		// The loop continues until the CertEnumCertificateContextProperties 
		// returns 0.

		while (dwPropId = CertEnumCertificateContextProperties(
			pCertContext, // the context whose properties are to be listed.
			dwPropId))    // number of the last property found. Must be
						  // 0 to find the first property ID.
		{
			//--------------------------------------------------------------------
			// Each time through the loop, a property ID has been found.
			// Print the property number and information about the property.

			printf("Property # %d found->", dwPropId);
			switch (dwPropId)
			{{
			case CERT_FRIENDLY_NAME_PROP_ID:
			{
				//--------------------------------------------------------------------
				//  Retrieve the actual display name certificate property.
				//  First, get the length of the property setting the
				//  pvData parameter to NULL to get a value for cbData
				//  to be used to allocate memory for the pvData buffer.
				printf("FRIENDLY_NAME_PROP_ID ");
				if (!(CertGetCertificateContextProperty(
					pCertContext,
					dwPropId,
					NULL,
					&cbData)))
				{
					MyHandleError("Call #1 to property length failed.");
				}
				//--------------------------------------------------------------------
				// The call succeeded. Use the size to allocate memory for the 
				// property.
				if (!(pvData = (void*)malloc(cbData)))
				{
					MyHandleError("Memory allocation failed.");
				}
				//--------------------------------------------------------------------
				// Allocation succeeded. Retrieve the property data.
				if (!(CertGetCertificateContextProperty(
					pCertContext,
					dwPropId,
					pvData,
					&cbData)))
				{
					MyHandleError("Call #2 getting the data failed.");
				}
				else
				{
					printf("\n  The display name is -> %S.", (wchar_t*)pvData);
					free(pvData);
				}
				break;
			}
			case CERT_SIGNATURE_HASH_PROP_ID:
			{
				printf("Signature hash ID. ");
				break;
			}
			case CERT_KEY_PROV_HANDLE_PROP_ID:
			{
				printf("KEY PROVE HANDLE.");
				break;
			}
			case CERT_KEY_PROV_INFO_PROP_ID:
			{
				printf("KEY PROV INFO PROP ID.");
				if (!(CertGetCertificateContextProperty(
					pCertContext,  // A pointer to the certificate
								   // where the property will be set.
					dwPropId,      // An identifier of the property to get. 
								   // In this case,
								   // CERT_KEY_PROV_INFO_PROP_ID
					NULL,          // NULL on the first call to get the
								   // length.
					&cbData)))     // The number of bytes that must be
								   // allocated for the structure.
				{
					MyHandleError("The property length was not retrieved.");
				}
				if (!(pCryptKeyProvInfo =
					(CRYPT_KEY_PROV_INFO *)malloc(cbData)))
				{
					MyHandleError("Error in allocation of memory.");
				}
				if (CertGetCertificateContextProperty(
					pCertContext,
					dwPropId,
					pCryptKeyProvInfo,
					&cbData))
				{
					printf("\n The current key container is %S.",
						pCryptKeyProvInfo->pwszContainerName);
					free(pCryptKeyProvInfo);
				}
				else
				{
					free(pCryptKeyProvInfo);
					MyHandleError("The property was not retrieved.");
				}
				break;
			}
			case CERT_SHA1_HASH_PROP_ID:
			{
				printf("SHA1 HASH id.");
				break;
			}
			case CERT_MD5_HASH_PROP_ID:
			{
				printf("md5 hash id. ");
				break;
			}
			case CERT_KEY_CONTEXT_PROP_ID:
			{
				printf("KEY CONTEXT PROP id.");
				break;
			}
			case CERT_KEY_SPEC_PROP_ID:
			{
				printf("KEY SPEC PROP id.");
				break;
			}
			case CERT_ENHKEY_USAGE_PROP_ID:
			{
				printf("ENHKEY USAGE PROP id.");
				break;
			}
			case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
			{
				printf("NEXT UPDATE LOCATION PROP id.");
				break;
			}
			case CERT_PVK_FILE_PROP_ID:
			{
				printf("PVK FILE PROP id. ");
				break;
			}
			case CERT_DESCRIPTION_PROP_ID:
			{
				printf("DESCRIPTION PROP id. ");
				break;
			}
			case CERT_ACCESS_STATE_PROP_ID:
			{
				printf("ACCESS STATE PROP id. ");
				break;
			}
			case CERT_SMART_CARD_DATA_PROP_ID:
			{
				printf("SMAART_CARD DATA PROP id. ");
				break;
			}
			case CERT_EFS_PROP_ID:
			{
				printf("EFS PROP id. ");
				break;
			}
			case CERT_FORTEZZA_DATA_PROP_ID:
			{
				printf("FORTEZZA DATA PROP id.");
				break;
			}
			case CERT_ARCHIVED_PROP_ID:
			{
				printf("ARCHIVED PROP id.");
				break;
			}
			case CERT_KEY_IDENTIFIER_PROP_ID:
			{
				printf("KEY IDENTIFIER PROP id. ");
				break;
			}
			case CERT_AUTO_ENROLL_PROP_ID:
			{
				printf("AUTO ENROLL id. ");
				break;
			}
			}}  // end switch
			printf("\n");
		} // end the inner while loop. This is the end of the display of
		  // a single property of a single certificate.

		My_Wait();
	} // end the outer while loop. Move on to the next certificate.

	  //--------------------------------------------------------------------
	  // Free Memory and close the open store.
	if (pCertContext)
	{
		CertFreeCertificateContext(pCertContext);
	}
	CertCloseStore(hCertStore, 0);
	printf("The function completed successfully.\n");
}

//--------------------------------------------------------------------
//  Define functions MyHandleError and My_Wait.

void MyHandleError(char *s)
{
	printf("%s\n", s);
	exit(1);
}

void My_Wait()
{

	printf("Hit enter to continue.");
	getchar();
}

